home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / info-service / gopher / incoming / linkmerge-0.1.shar / linkmerge < prev    next >
Encoding:
Text File  |  1993-04-15  |  13.7 KB  |  416 lines

  1. #!/usr/local/bin/perl
  2. #
  3. # linkmerge 0.1 -- merge a group of links to gopher resources
  4. #
  5. # usage: linkmerge < links-to-dirs-to-be-merged > .merged-links
  6. #
  7. # Linkmerge is intended as a way to make use of efforts elsewhere in
  8. # Gopherspace to gather collections of Internet resources organized
  9. # by subject.  Linkmerge examines a specified set of Gopher directories
  10. # and produces a merged list of links to their contents.  It makes an
  11. # attempt to eliminate duplicate links and to resolve WAIS and go4gw
  12. # resources to use local servers.  Linkmerge also allows for a "stop
  13. # list" of resources which it should suppress in its output.
  14. #
  15. #
  16. # INPUT FORMAT:
  17. # The input consists of gopher links to the directories to be merged,
  18. # as well as individual resources to be suppressed, in the following
  19. # format (note that the tabs are essential):
  20. #
  21. #    merge <tab> path <tab> host <tab> port
  22. #    stop  <tab> path <tab> host <tab> port
  23. #
  24. # OUTPUT FORMAT:
  25. # The output is in the format of a gopherd .links file with comments to
  26. # help in debugging, e.g.:
  27. #
  28. #    # Merging 1/.dir/ams.taes.ag.resource tamuts.tamu.edu 70
  29. #    # Merging 1/catalog/Agriculture flubber.ciesin.org 70
  30. #    # Merging 1/Selected/Agriculture hunter.unr.edu 70
  31. #    
  32. #    Name=CYFER-net USDA ES Gopher Server.
  33. #    #     from tamuts.tamu.edu
  34. #    Path=
  35. #    Host=cyfer.esusda.gov
  36. #    Port=70
  37. #    Type=1
  38. #    #Also CYFER-net USDA ES Gopher Server.
  39. #    #     from flubber.ciesin.org
  40. #    
  41. #    Name=Agricola
  42. #    #     from tamuts.tamu.edu
  43. #    Path=
  44. #    Host=isn.iastate.edu
  45. #    Port=0
  46. #    Type=8
  47. #    #Also Agricola
  48. #    #     from flubber.ciesin.org
  49. #    
  50. #    Name=QUERRI (Database for North Central States)
  51. #    #     from hunter.unr.edu
  52. #    Path=
  53. #    Host=isn.rdns.iastate.edu
  54. #    Port=0
  55. #    Type=8
  56. #
  57. #
  58. # RESOURCE RESOLUTION:
  59. # When two or more of the input directories list the same resource, the
  60. # name in the output will be taken from the first input directory which
  61. # contained it.  For this reason, more trustworthy or better-designed
  62. # input directories should be listed first.
  63. #
  64. # If the following configuration variables are defined below, this program
  65. # will try to resolve links to WAIS indexes to a local copy:
  66. #    $waisdir $waishost $waispath $waisport
  67. #
  68. # If the following configuration variables are defined below, this program
  69. # will resolve remote go4gw links to use a local go4gw server:
  70. #    $go4gwhost $go4gwport @go4gwserv
  71. #
  72. # Note that "stop" operations take place *after* the above resolutions.
  73. #
  74. #
  75. # EXAMPLE:
  76. # Here is a simple shell script using linkmerge which could be called from
  77. # crontab.
  78. #
  79. #    #!/bin/csh -f
  80. #    #
  81. #    # Script to use linkmerge to merge several collections of
  82. #    # agriculture resources.
  83. #    #
  84. #    set MERGE="/foo/cwis/bin/linkmerge"
  85. #    set SUBJDIR="/foo/cwis/gopher/world/BySubject"
  86. #    
  87. #    if ( -f $SUBJDIR/Agriculture/.mergelinks ) then
  88. #        /bin/mv -f $SUBJDIR/Agriculture/.mergelinks \
  89. #            $SUBJDIR/.oldlinks/Agriculture
  90. #    endif
  91. #    $MERGE > $SUBJDIR/Agriculture/.mergelinks <<'EOF'
  92. #    merge    1/.dir/ams.taes.ag.resource    tamuts.tamu.edu    70
  93. #    merge    1/catalog/Agriculture    flubber.ciesin.org    70
  94. #    stop    1/.data/owl-eradication    tamuts.tamu.edu    70
  95. #    'EOF'
  96. #
  97. #----------------------------------------------------------------------------
  98. # History:
  99. # 03/18/93 PASR  Original version by Prentiss Riddle (riddle@rice.edu), but
  100. #                based on gopherclone by Bob Alberti
  101. #                (alberti@boombox.micro.umn.edu) and friends:
  102. #                   original NNTP client suggested by eci386!clewis
  103. #                   socket code by cmf@obie.cis.pitt.edu (Carl M. Fongheiser)
  104. #                   adaptation for gopher by emv@msen.com (Edward Vielmetti)
  105. #                   mods to indexer by Bob Alberti
  106. # 03/25/93 PASR  Declared this version 0.1 and posted it to the net.
  107. #----------------------------------------------------------------------------
  108. #
  109. # CONFIGURATION -- set these variables to suit your site
  110.  
  111. $debug = 1;        # Turn off for fewer comments in output
  112.  
  113. # Local Gopher/WAIS configuration information.  Define these variables
  114. # if a Gopher server on the local machine contains an extensive directory
  115. # of WAIS sources and you'd rather make WAIS queries via your local Gopher
  116. # server than a remote Gopher server.  If you do not wish to use this
  117. # feature, leave these variables undefined.
  118. #
  119. # Note that the program will *look* for a matching WAIS ".src" file on
  120. # the local machine and only transform the link to use it if a match is
  121. # found.  It will look in two places: (1) the directory $dir and (2) a
  122. # subdirectory  of $dir consisting of the first letter of the name of
  123. # the WAIS source (e.g., "$dir/Foobar.src" and "$dir/f/Foobar.src").
  124. #
  125. # Variables:
  126. #   $waishost   hostname of your Gopher server (should be this machine)
  127. #   $waisport   port number of your Gopher server
  128. #   $waisdir    full Unix directory in which to look for WAIS sources
  129. #   $waispath   Gopher path (i.e., relative to the top of your Gopher tree)
  130. #                  of your WAIS sources
  131. # Example:
  132. #   $waishost = "gopher.foobar.edu";
  133. #   $waisport = 70;
  134. #   $waisdir = "/usr/gopher/Other/WAIS";
  135. #   $waispath = "/Other/WAIS";
  136. $waishost = "riceinfo.rice.edu";
  137. $waisport = 70;
  138. $waisdir = "/chico-b/cwis/gopher/world/OtherGophers/WAIS";
  139. $waispath = "/OtherGophers/WAIS";
  140.  
  141. # Host and port of your local go4gw gateway and the services which it
  142. # provides.  Define these if you run a go4gw gateway and you wish for
  143. # links to be translated to use it instead of remote go4gw gateways.
  144. # (Note: this could backfire if there are non-go4gw paths which look
  145. # like go4gw ones.)
  146. #
  147. # If you do not wish to use this feature (or if you don't know what go4gw
  148. # does :-) ), leave these variables undefined.
  149. #
  150. # Variables:
  151. #   $go4gwhost   hostname of host where your go4gw gateway runs
  152. #   $go4gwport   port number of your go4gw gateway
  153. #   @go4gwserv   list of go4gw services you wish to have translated
  154. #
  155. # Example:
  156. #   $go4gwhost = "gopher.foobar.edu";
  157. #   $go4gwport = 9999;
  158. #   @go4gwserv = ("areacode", "ftp", "geo", "nntp");
  159. $go4gwhost = "riceinfo.rice.edu";
  160. $go4gwport = 1103;
  161. @go4gwserv = ("areacode", "geo", "nntp");
  162.  
  163. # END OF CONFIGURATION SECTION 
  164. #----------------------------------------------------------------------------
  165. #
  166. #Data structures:
  167. #
  168. # @merge    A list of links to Gopher directories to be merged.
  169. #        Its values consist of tab-separated Gopher links in the
  170. #        form "path<tab>host<tab>port".
  171. #
  172. # %stop        A table of links to resources to be suppressed.  Its
  173. #               indexes consist of tab-separated Gopher links in the
  174. #               form "path<tab>host<tab>port".  It returns "1"
  175. #        for any resource which appeared in a "stop" line on
  176. #        input.  Gopher links used to index it should be forced
  177. #               to lowercase prior to insertion or lookup in order to
  178. #               eliminate mismatches caused by case distinction.
  179. #
  180. # %links    A table of all of the Gopher links we've seen so far.  Its
  181. #        indexes consist of tab-separated Gopher links in the
  182. #        form "path<tab>host<tab>port<tab>type".  The values it
  183. #        returns are the numeric indices of the other tables
  184. #        here.  Gopher links used to index it should be forced
  185. #        to lowercase prior to insertion or lookup in order to
  186. #        eliminate false duplicates caused by case distinction.
  187. #
  188. # @paths    The path of each link, indexed by a value returned by
  189. #        $links[].
  190. #
  191. # @hosts    The host of each link, indexed by a value returned by
  192. #        $links[].
  193. #
  194. # @ports    The port of each link, indexed by a value returned by
  195. #        $links[].
  196. #
  197. # @types    The type of each link, indexed by a value returned by
  198. #        $links[].
  199. #
  200. # @names    The names associated with each link, indexed by a value
  201. #        returned by $links[].  Each value returned by $names[]
  202. #        can have multiple tab-separated names, but only the
  203. #        first is used to generate a "live" link in the output;
  204. #        the others are available for debugging purposes.
  205. #
  206. # @viahosts    The hosts where each link was found, indexed by a value
  207. #        returned by $links[].  Each value returned by $viahosts[]
  208. #        can have multiple tab-separated hostnames.  This
  209. #        information is kept for debugging purposes.
  210. #
  211. # $nlinks    Number of entries (starting with 1) in the lists indexed
  212. #        by %links.
  213. #----------------------------------------------------------------------------
  214.  
  215. # Here's how to make your own socket.ph:
  216. #    cp /usr/include/sys/socket.h socket.h
  217. require 'socket.ph';  # h2ph socket
  218.  
  219. # Read the input and save it into @merge and %stop.
  220. while (<STDIN>) {
  221.     chop;
  222.     $op = "";
  223.     ($op, $path, $host, $port) =
  224.         /^(\S*) *\t([^\t]*)\t(\S+)\t(\d+)$/;
  225.     if ($op eq "stop") {
  226.         # Add it to the stop list.
  227.         $link = "$path\t$host\t$port";
  228.         $link =~ tr/A-Z/a-z/;
  229.         $stop{$link} = 1;
  230.         print("# Stop  $link\n");
  231.         next;
  232.     }
  233.     unless ($op eq "merge") {
  234.         print("# UNRECOGNIZED INPUT: $_\n");
  235.         next;
  236.     }
  237.     push(@merge, "$path\t$host\t$port");
  238.     print("# Merge $path $host $port\n");
  239. }
  240. print("#\n");
  241.  
  242. # Step through the links in @merge.
  243. $nlinks = 0;
  244. while ($mergelink = shift(@merge)) {
  245.     print("# Merging $mergelink\n");
  246.     ($path, $viahost, $port) = split(/\t/, $mergelink);
  247.  
  248.     # Make sure the path has an initial type selector (default "1/").
  249.     $path =~ s#^/#1/#;
  250.     unless ($path =~ m#^1/#) {
  251.         print("#         ^ BAD PATH -- IGNORED!\n");
  252.         next;
  253.     }
  254.     unless ($viahost && $port && $path) {
  255.         print("#         ^ INCOMPLETE PATH/HOST/PORT -- IGNORED!\n");
  256.         next;
  257.     }
  258.     
  259.     chop($hostname = `hostname`);    # get host name in variable
  260.     ($N) = &tcpconnect($viahost, $hostname);
  261.     unless ($N) {
  262.         # bad connection
  263.         print("#         ^ COULDN'T OPEN TCP CONNECTION $N!\n");
  264.         next;
  265.     }
  266.     send(N,"$path\r\n", 0)
  267.         || die "Send $d to $viahost barfed with: $!\n";
  268.     while (<N>) {
  269.         last if /^\.\r\n$/;    # loop til lone period
  270.         if (m#^(.)(.*)\t([^\t]*)\t([^\t]+)\t(\d+)\s*$#) {
  271.             # We have a link to process.
  272.             $type = $1;
  273.             $name = $2;
  274.             $path = $3;
  275.             $host = $4;
  276.             $port = $5;
  277.             $host =~ s/^\s*//;
  278.             $host =~ s/\s*$//;
  279.             $name =~ s/^\s*//;
  280.             $name =~ s/\s*$//;
  281.             &normalize();
  282.  
  283.             # Is this on our stop list?
  284.             $link = "$path\t$host\t$port";
  285.             $link =~ tr/A-Z/a-z/;
  286.             #print ("# Checking \"$link\"\n") if $debug;
  287.             if ($stop{$link}) {
  288.                 print("# STOPPED $name: $path\t$host\t$port\t$type\n") if $debug;
  289.                 next;
  290.             }
  291.  
  292.             # Re-make the link the way %links needs it. :-(
  293.             $link = "$path\t$host\t$port\t$type";
  294.             $link =~ tr/A-Z/a-z/;
  295.  
  296.             # Have we seen this one before?
  297.             if ($links{$link}) {
  298.                 # Save all names & viahosts, even for
  299.                 # links we've seen.
  300.                 $l = $links{$link};
  301.                 $names[$l] .= "$name\t";
  302.                 $viahosts[$l] .= "$viahost\t";
  303.             } else {
  304.                 # Nope -- save it.
  305.                 $links{$link} = ++$nlinks;
  306.                 $paths[$nlinks] = $path;
  307.                 $hosts[$nlinks] = $host;
  308.                 $ports[$nlinks] = $port;
  309.                 $types[$nlinks] = $type;
  310.                 $names[$nlinks] = "$name\t";
  311.                 $viahosts[$nlinks] = "$viahost\t";
  312.             }
  313.             print("#         $name: $path\t$host\t$port\t$type\n") if $debug;
  314.         } else {
  315.             print("#         ^ BAD MATCH: $_\n");
  316.         }
  317.     }
  318.     close(N);
  319. }
  320. undef(%links);        # don't need this any more...
  321.  
  322. # Now unroll our data structures and generate a report in the form of
  323. # a Gopher ".links" file.
  324. for ($l = 1; $l <= $nlinks; $l++ ) {
  325.     @thesenames = split(/\t/, $names[$l]);
  326.     @theseviahosts = split(/\t/, $viahosts[$l]);
  327.     print("\nName=$thesenames[0]\n#     from $theseviahosts[0]\n");
  328.     print("Path=$paths[$l]\n");
  329.     print("Host=$hosts[$l]\n");
  330.     print("Port=$ports[$l]\n");
  331.     print("Type=$types[$l]\n");
  332.     for ($i = 1; $i <= $#thesenames; $i++) {
  333.         print("#Also $thesenames[$i]\n");
  334.         print("#     from $theseviahosts[$i]\n");
  335.     }
  336. }
  337.  
  338. #----------------------------------------------------------------------------
  339. # Normalize a gopher link prior to saving it in %linktab.
  340. # Our goal here is largely to resolve duplicates, but we also translate
  341. # some links to remote servers to use local ones if possible.
  342. #
  343. # Global variables used:
  344. #    $host $name $path $port $type
  345. #    $go4gwhost $go4gwport @go4gwserv
  346. #    $waisdir $waishost $waispath $waisport
  347.  
  348. sub normalize {
  349.     local($firstchar, $service, $waissrc);
  350.  
  351.     # Try to resolve WAIS sources to something available locally.
  352.     # Look in both $waisdir and subdirectories based on its first char.
  353.     if ($type eq "7" && $path =~ m#waissrc:.*/([^/*]+.src)#) {
  354.         # WAIS source -- is this available locally?
  355.         $waissrc = $1;
  356.         $firstchar = substr($waissrc, 0, 1);
  357.         $firstchar =~ tr/A-Z/a-z/;
  358.         if (-d $waisdir && -f "$waisdir/$waissrc") {
  359.             $host = $waishost;
  360.             $port = $waisport;
  361.             $path = "waissrc:$waispath/$waissrc";
  362.         } elsif (-d "$waisdir/$firstchar" &&
  363.                 -f "$waisdir/$firstchar/$waissrc") {
  364.             $host = $waishost;
  365.             $port = $waisport;
  366.             $path = "waissrc:$waispath/$firstchar/$waissrc";
  367.         }
  368.     }
  369.  
  370.     # Try to resolve remote go4gw gateways to the local one.
  371.     # (Note: this could backfire if there are non-go4gw paths which
  372.     # look like go4gw ones.)
  373.     if ($go4gwhost) {
  374.         ($service) = $path =~ /^(\w*)/;
  375.         if ($service && grep(/$service/, @go4gwserv)) {
  376.             $host = $go4gwhost;
  377.             $port = $go4gwport;
  378.         }
  379.     }
  380.     if ($path =~ /^nntp / && $nntphost && $nntpport) {
  381.         $host = $nntphost;
  382.         $port = $nntpport;
  383.     }
  384.  
  385.     # TO DO: substitute a local g2ftp gateway.
  386. }
  387.  
  388. #----------------------------------------------------------------------------
  389. sub tcpconnect {                    #Get TCP info in place
  390.    local($host, $hostname) = @_;
  391.    $sockaddr = 'S n a4 x8';
  392.  
  393.  
  394.    ($name,$aliases,$proto) = getprotobyname('tcp');
  395.    ($name,$aliases,$port) = getservbyname($port, 'tcp')
  396.         unless $port =~ /^\d+$/;
  397.    ($name,$aliases,$type,$len,$thisaddr) = gethostbyname($hostname);
  398.    ($name,$aliases,$type,$len,$thataddr) = gethostbyname($host);
  399.  
  400.    $this = pack($sockaddr, &AF_INET, 0, $thisaddr);
  401.    $that = pack($sockaddr, &AF_INET, $port, $thataddr);
  402.  
  403.    sleep(2);
  404.  
  405.    #socket(N, &PF_INET, &SOCK_STREAM, $proto) || die "socket: $!";
  406.    #bind(N, $this)                            || die "bind: $!";
  407.    #connect(N, $that)                         || die "connect: $!";
  408.    socket(N, &PF_INET, &SOCK_STREAM, $proto) || return 0;
  409.    bind(N, $this)                            || return 0;
  410.    connect(N, $that)                         || return 0;
  411.  
  412.    return(N);
  413. }
  414. #----------------------------------------------------------------------------
  415. # end of linkmerge
  416.